/*
 * This file is part of the Code::Blocks IDE and licensed under the GNU Lesser General Public License, version 3
 * http://www.gnu.org/licenses/lgpl-3.0.html
 */

#ifndef MANAGER_H
#define MANAGER_H

#include <map>
#include <vector>

#ifndef WX_PRECOMP
#   ifdef __WXMSW__
/*需要防止让出CPU时间片定义错误.*/
#       include <wx/msw/wrapwin.h>
#   endif
#endif
#include <wx/event.h>
#include <wx/cmdline.h>

#include "settings.h"
#include "sdk_events.h"
#include "cbfunctor.h"
#include "cbexception.h"

/*前置声明使用到的类[标准调用]*/
class wxFrame;
class wxWindow;
class ProjectManager;
class EditorManager;
class DebuggerManager;
class LogManager;
class PluginManager;
class ToolsManager;
class MacrosManager;
class PersonalityManager;
class wxMenu;
class wxMenuBar;
class wxToolBar;
class UserVariableManager;
class ScriptingManager;
class ConfigManager;
class FileManager;
class ColourManager;
/*代码自动补全管理器*/
class CCManager;
class cbSearchResultsLog;

/**
 * 对于linux来说class DLLIMPORT应该是静态库如*.so里可导入的类
 * 使用了(DLLEXPORT)关键字,相当于声明了紧接在(DLLEXPORT)关键字后面的相关内容是可以为其他程序使用的.
 * 而(DLLIMPORT)关键字是在外部程序需要使用DLL内相关内容时使用的关键字.
 *
 * 当一个外部程序要使用DLL内部代码(类,函数,全局变量)时,
 * 只需要在程序内部使用(DLLIMPORT)关键字声明需要使用的代码就可以了,
 * 即(DLLIMPORT)关键字是在外部程序需要使用DLL内部相关内容的时候才使用.
 *
 * (DLLIMPORT)作用是把DLL中的相关代码插入到应用程序中.
 *
 * DLLIMPORT具有平台特性,不同平台使用具名方式相同,声明方式不同.
 * DLLIMPORT对于类意思为可导入的类.
 * 与之对应是DLLEXPORT
 */
class DLLIMPORT Manager
{
    wxFrame*               m_pAppWindow;
    static bool            m_AppShuttingDown;
    static bool            m_AppStartedUp;
    static bool            m_BlockYields;
    static bool            m_IsBatch;
    static wxCmdLineParser m_CmdLineParser;

     Manager();
    ~Manager();

    void OnMenu(wxCommandEvent& event);

public:
    static void SetAppStartedUp(bool app_started_up);
    static void SetAppShuttingDown(bool app_shutting_down);
    static void SetBatchBuild(bool is_batch);
    static bool IsBatchBuild() { return m_IsBatch; }

    /*阻塞/非阻塞 管理器Yield函数,需小心使用,通常不去使用*/
    static void BlockYields(bool block);
    /*每当需要调用wxYield()时,请调用Manager::Yield().这样比较安全.*/
    static void Yield();
    static void ProcessPendingEvents();
    static void Shutdown();

    bool ProcessEvent(CodeBlocksEvent&       event);
    bool ProcessEvent(CodeBlocksDockEvent&   event);
    bool ProcessEvent(CodeBlocksLayoutEvent& event);
    bool ProcessEvent(CodeBlocksLogEvent&    event);

    /*使用Manager::Get()获取指向其实例Manager::Get()的指针保证永远不会返回无效指针.*/
    static Manager* Get();
    /*永远不要,永远不要,调用这个函数!这是关闭时调用的最后一个函数....*/
    static void Free();

    wxFrame*  GetAppFrame()  const;
    wxWindow* GetAppWindow() const;

    static bool IsAppShuttingDown();
    static bool IsAppStartedUp();

    /**
     * 函数返回指向相应子管理器实例的指针.
     * 在应用程序启动和运行时,这些函数将始终返回有效的指针.
     * 在应用程序关闭期间,这些函数将继续返回有效指针,直到请求的管理器关闭.
     * 从那时起,下面的函数将返回null.如果在应用程序关闭期间有可能执行代码,则必须检查空指针.
     * 此规则的一个显著例外是ConfigManager[配置管理器],它与管理器本身具有相同的生存期.
     *
     * 销毁顺序为:
     * ----------------------------
     *   ToolsManager[工具管理器],
     *   TemplateManager[模板管理器],
     *   PluginManager[插件管理器],
     *   ScriptingManager[脚本管理器],
     *   ProjectManager[项目管理器],
     *   EditorManager[编辑器管理器],
     *   PersonalityManager[个性化管理器],
     *   MacrosManager[宏管理器],
     *   UserVariableManager[用户变量管理器],
     *   LogManager[日志管理器]
     *
     *   ConfigManager[配置管理器]在应用程序终止之前立即被销毁,因此可以认为它无所不在.
     *   对于插件开发人员来说,这意味着大多数管理器(除了那些你可能根本不使用的管理器)在插件的整个生命周期中都是可用的.
     *   (只读的成员函数,输出的常量型对象成员)
     *
     */

    ProjectManager*      GetProjectManager()                          const;
    EditorManager*       GetEditorManager()                           const;
    LogManager*          GetLogManager()                              const;
    PluginManager*       GetPluginManager()                           const;
    ToolsManager*        GetToolsManager()                            const;
    MacrosManager*       GetMacrosManager()                           const;
    PersonalityManager*  GetPersonalityManager()                      const;
    UserVariableManager* GetUserVariableManager()                     const;
    ScriptingManager*    GetScriptingManager()                        const;
    ConfigManager*       GetConfigManager(const wxString& name_space) const;
    FileManager*         GetFileManager()                             const;
    DebuggerManager*     GetDebuggerManager()                         const;
    ColourManager*       GetColourManager()                           const;
    CCManager*           GetCCManager()                               const;


    /*XML资源函数 初始化XML资源系统*/
    static void InitXRC(bool force=false);
    /*使用数据路径加载XRC文件*/
    static void LoadXRC(wxString relpath);
    /*从压缩包中载入资源文件*/
    static bool LoadResource(const wxString& file);
    /*从XRC加载菜单栏*/
    static wxMenuBar* LoadMenuBar(wxString resid, bool createonfailure = false);
    /*从XRC加载菜单*/
    static wxMenu*    LoadMenu(wxString menu_id, bool createonfailure = false);
    /*从XRC加载工具条*/
    static wxToolBar* LoadToolBar(wxFrame *parent, wxString resid, bool defaultsmall = true);
    /*不要使用这个,使用Get()*/
    static Manager* Get(wxFrame* appWindow);

    wxToolBar* CreateEmptyToolbar();
    static void AddonToolBar(wxToolBar* toolBar,wxString resid);
    static bool isToolBar16x16(wxToolBar* toolBar);

    static wxCmdLineParser* GetCmdLineParser();

    /*事件接收[事件类型,接口泛型仿函数]*/
    void RegisterEventSink(wxEventType eventType, IEventFunctorBase<CodeBlocksEvent>*       functor);
    void RegisterEventSink(wxEventType eventType, IEventFunctorBase<CodeBlocksDockEvent>*   functor);
    void RegisterEventSink(wxEventType eventType, IEventFunctorBase<CodeBlocksLayoutEvent>* functor);
    void RegisterEventSink(wxEventType eventType, IEventFunctorBase<CodeBlocksLogEvent>*    functor);
    void RemoveAllEventSinksFor(void* owner);

    /*返回指向搜索结果记录器的指针,可能为空指针[nullptr]或隐藏.*/
    cbSearchResultsLog* GetSearchResultLogger() const { return m_SearchResultLog; }
    /*设置指向搜索结果记录器的指针,用户不得调用此方法.*/
    void SetSearchResultLogger(cbSearchResultsLog *log) { m_SearchResultLog = log; }

private:
    /*定义新容器类型*/
    typedef std::vector< IEventFunctorBase<CodeBlocksEvent>* >       EventSinksArray;
    typedef std::map< wxEventType, EventSinksArray >                 EventSinksMap;
    typedef std::vector< IEventFunctorBase<CodeBlocksDockEvent>* >   DockEventSinksArray;
    typedef std::map< wxEventType, DockEventSinksArray >             DockEventSinksMap;
    typedef std::vector< IEventFunctorBase<CodeBlocksLayoutEvent>* > LayoutEventSinksArray;
    typedef std::map< wxEventType, LayoutEventSinksArray >           LayoutEventSinksMap;
    typedef std::vector< IEventFunctorBase<CodeBlocksLogEvent>* >    LogEventSinksArray;
    typedef std::map< wxEventType, LogEventSinksArray >              LogEventSinksMap;

    EventSinksMap       m_EventSinks;
    DockEventSinksMap   m_DockEventSinks;
    LayoutEventSinksMap m_LayoutEventSinks;
    LogEventSinksMap    m_LogEventSinks;
    cbSearchResultsLog *m_SearchResultLog;
};

template <class MgrT> class DLLIMPORT Mgr
{
    static MgrT *instance;
    static bool isShutdown;
    explicit Mgr(const Mgr<MgrT>&)         { ; };
    Mgr<MgrT>& operator=(Mgr<MgrT> const&) { ; };

protected:

    Mgr()          { assert(Mgr<MgrT>::instance == nullptr); }
    virtual ~Mgr() { Mgr<MgrT>::instance = nullptr; }

public:

    static bool Valid() { return instance; }

    static MgrT* Get()
    {
        if (instance == nullptr)
        {
            if (isShutdown == false)
                instance = new MgrT();
            else
                cbAssert(false && "在子系统关闭后调用Get是一个错误!");
        }
        return instance;
    }

    static void Free()
    {
        isShutdown = true;
        delete instance;
        instance = nullptr;
    }
};

#endif // MANAGER_H
